package pers.whj.rpc.transport;

import pers.whj.rpc.common.Config;
import pers.whj.rpc.protocol.Address;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * 实现客户端通信接口，采用TCP连接
 */
public class TCPClient implements TransportClient {
    private final Socket socket;
    private InetSocketAddress address;
    private DataInputStream input;
    private DataOutputStream output;

    public TCPClient() {
        socket = new Socket();
        address = null;
    }

    @Override
    public void connect(Address address) throws Exception {
        if (address == null) {
            throw new IllegalArgumentException("address is null");
        }
        this.address = new InetSocketAddress(address.getHost(), address.getPort());
        socket.connect(this.address, Config.TIME_OUT_CONNECT);
        socket.setSoTimeout(Config.TIME_OUT_CLIENT_READ);
        input = new DataInputStream(socket.getInputStream());
        output = new DataOutputStream(socket.getOutputStream());
        if (Config.DEBUG) {
            System.out.println("成功连接到服务器：" + address);
        }
    }

    @Override
    public byte[] write(byte[] data) throws Exception {
        if (data == null) {
            throw new IllegalArgumentException("data is null");
        }
        if (data.length > 0) {
            int index = 1;
            //发送数据，失败则再次发送，有上限
            while (index <= Config.CLIENT_REPEAT_COUNT) {
                try {
                    //发送数据
                    output.writeInt(data.length);
                    output.write(data, 0, data.length);
                    output.flush();
                    //读取数据
                    return TransportUtils.readData(input, input.readInt());
                } catch (Exception e) {
                    index++;
                }
            }
            throw new Exception("服务端未响应！");
        } else {
            return new byte[0];
        }
    }

    @Override
    public void close() {
        try {
            if (output != null) {
                output.writeInt(Config.DATA_LENGTH_LIMIT_TO_END);
                output.flush();
                output.close();
            }
            if (input != null) {
                input.close();
            }
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
